package api.action;

import api.model.ApiAuthinfo;
import api.model.ApiMigration;
import api.service.ApiAuthinfoService;
import api.service.ApiMigrationService;
import api.util.ApiMigrationSaveProgress;
import com.alibaba.fastjson.JSONObject;
import m.common.action.ActionMeta;
import m.common.action.RequestMeta;
import m.common.action.VueResult;
import m.common.model.Model;
import m.common.model.util.ModelQueryList;
import m.common.model.util.ModelUpdateUtil;
import m.common.model.util.QueryCondition;
import m.html.VueFormResult;
import m.html.VueListResult;
import m.html.element.attr.Align;
import m.html.element.attr.ButtonType;
import m.html.element.attr.TagColor;
import m.html.form.*;
import m.html.list.*;
import m.system.db.TransactionManager;
import m.system.exception.MException;
import m.system.util.ClassUtil;
import m.system.util.JSONMessage;
import m.system.util.StringUtil;
import manage.action.ManageAction;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@ActionMeta(name="api/apiMigration")
public class ApiMigrationAction extends ManageAction {
    private ApiMigration model;
    private void verifyAuth() throws MException {
        getService(ApiAuthinfoService.class).auth(getAuthorization(), ApiAuthinfo.Type_Inter, true);
    }
    /**
     * 验证模型类是否存在
     */
    @RequestMeta(params = {"tableClass","oidList"})
    public JSONMessage verifyModel(String tableClass,List<String> oidList) throws MException, ClassNotFoundException, SQLException {
        verifyAuth();
        Class<? extends Model> clazz = ClassUtil.getClass(Model.class, tableClass);
        List<String> hasList =new ArrayList<>();
        List<String> ls=new ArrayList<>();
        for(int i=0;i<oidList.size();i++) {
            if(i!=0&&i%999==0||i==oidList.size()-1) {
                List<String> hs = ModelQueryList.getModelList(clazz, new String[]{"oid"}, null,
                                QueryCondition.in("oid", ls.toArray(new Object[0])))
                        .stream().map(Model::getOid).collect(Collectors.toList());
                hasList.addAll(hs);
                ls.clear();
            }else{
                ls.add(oidList.get(i));
            }
        }
        if(!hasList.isEmpty()){
            List<String> error=new ArrayList<>();
            if(hasList.size()>10){
                error.add("数量"+hasList.size()+"个");
                for(int i=0;i<10;i++) error.add(hasList.get(i));
                error.add("...");
            }else{
                error=hasList;
            }
            return JSONMessage.error("已存在oid").push("error",error);
        }
        return JSONMessage.success("验证通过");
    }

    /**
     * 接收数据迁移
     */
    @RequestMeta(transaction = true,params = {"tableClass","modelList"})
    public JSONMessage saveModelList(String tableClass, List<JSONObject> modelList) throws Exception {
        verifyAuth();
        new ApiMigrationSaveProgress(tableClass,modelList).saveAll();
        return JSONMessage.success("接收成功");
    }
    public JSONMessage doDelete() throws Exception {
        verifyAdminOperPower("manage_api_power");//权限判断
        getService(ApiMigrationService.class).delete(model);
        return JSONMessage.success("删除成功");
    }
    public JSONMessage doSave() throws Exception {
        verifyAdminOperPower("manage_api_power");//权限判断
        return JSONMessage.success(getService(ApiMigrationService.class).save(model));
    }
    public JSONMessage doCheck() throws Exception {
        verifyAdminOperPower("manage_api_power");//权限判断
        ApiMigrationService service=getService(ApiMigrationService.class);
        String msg=service.save(model)+"，已启动校验。";
        new Thread(() -> {
            try {
                model.setStatus(ApiMigration.Status_Check);
                model.setErrorMessage(null);
                ModelUpdateUtil.updateModel(model,"status","errorMessage");
                service.check(model);
            } catch (Exception e) {
                try {
                    model.setStatus(ApiMigration.Status_Error);
                    String emsg=e.getMessage();
                    model.setErrorMessage(emsg.length()>999?emsg.substring(0,999):emsg);
                    ModelUpdateUtil.updateModel(model,"status","errorMessage");
                } catch (MException ex) {
                    throw new RuntimeException(ex);
                }
            } finally {
                TransactionManager.closeConnection();
            }
        }).start();
        Thread.sleep(300);
        return JSONMessage.success(msg);
    }
    public JSONMessage doMigration() throws Exception {
        getService(ApiMigrationService.class).startMigration(model.getOid());
        return JSONMessage.success("操作成功");
    }
    public JSONMessage stopMigration() throws Exception {
        getService(ApiMigrationService.class).stopMigration(model.getOid());
        return JSONMessage.success("操作成功");
    }
    /*
     * 编辑数据迁移
     */
    public VueResult toEdit() throws Exception {
        verifyAdminOperPower("manage_api_power");//权限判断
        if(null!=model&&!StringUtil.isSpace(model.getOid())){
            model= ModelQueryList.getModel(model,"*");
        }else{
            model=new ApiMigration();
            model.setVerifyOid(ApiMigration.Verify_Oid_No);
        }
        ModelForm form = new ModelForm("数据迁移",2);
        form.addItem(
            FormInput.input("描述", "model.description").setSpan(2).setPlaceholder("请输入描述"),
            FormInput.input("服务地址", "model.serverUrl").setPlaceholder("请输入服务地址，例如：http://0.0.0.0:80"),
            FormInput.radio("校验主键","model.verifyOid","api.model.ApiMigration!verifyOid"),
            FormInput.input("迁移参数", "model.param").setPlaceholder("请输入迁移参数"),
            FormInput.integer("进程数量", "model.threadNum").setPlaceholder("请输入进程数量"),
            FormInput.input("鉴权id", "model.authId").setPlaceholder("请输入鉴权id"),
            FormInput.input("鉴权key", "model.authKey").setPlaceholder("请输入鉴权key")
        )
        .addData("model",model)
        .addButton(
            FormButton.pri("保存","doSave"),
            FormButton.succ("保存并校验","doCheck")
        )
        .addMethod(
            FormEvent.backFlag,
            FormEvent.doJson("doSave",actionUrl("doSave"),"{model:this.model}")
                .success("backFlag"),
            FormEvent.doJson("doCheck",actionUrl("doCheck"),"{model:this.model}")
                .success("backFlag")
        );
        VueFormResult result=new VueFormResult();
        return result.addForm(form);
    }
    public VueResult toView() throws Exception {
        verifyAdminOperPower("manage_api_power");//权限判断
        if(null!=model&&!StringUtil.isSpace(model.getOid())){
            model= ModelQueryList.getModel(model,"*");
        }else{
            throw new MException(this.getClass(),"参数错误");
        }
        ModelForm form = new ModelForm("数据迁移");
        form.addItem(
            FormHtml.inputStyle("描述", "{{model.description}}").setSpan(2),
            FormHtml.inputStyle("状态", "{{dict('api.model.ApiMigration!status',model.status)}} {{model.status=='"+ApiMigration.Status_Migration+"'||model.status=='"+ApiMigration.Status_Migration_Stop+"'?formatNumber(model.exeProgress,'0.00%'):''}}"),
            FormHtml.inputStyle("服务地址", "{{model.serverUrl}}"),
            FormHtml.inputStyle("校验主键","{{dict('api.model.ApiMigration!verifyOid',model.verifyOid)}}"),
            FormHtml.inputStyle("进程数量", "{{model.threadNum}}"),
            FormHtml.inputStyle("鉴权id", "{{model.authId}}"),
            FormHtml.inputStyle("鉴权key", "{{model.authKey}}"),
            FormHtml.inputStyle("迁移参数", "{{model.param}}"),
            FormHtml.inputStyle("记录数量", "{{model.recordNum}}"),
            FormHtml.inputStyle("成功数量", "{{model.successNum}}"),
            FormHtml.inputStyle("失败数量", "{{model.errorNum}}")
        )
        .addData("model",model);
        LoadPage tablesPage=new LoadPage("loadTablesPage",
                actionUrl(ApiMigrationTableAction.class,"tableList"),"{params:{'migration.oid':this.model.oid}}")
                .setMounted("this.loadTablesPage();");
        VueFormResult result=new VueFormResult();
        return result.addForm(form).addForm(tablesPage);
    }
    private static Map<String, TagColor> statusMap=null;
    public static Map<String, TagColor> getStatusColorMap(){
        if(null==statusMap){
            statusMap=new HashMap<>();
            statusMap.put(ApiMigration.Status_Edit,TagColor.Processing);
            statusMap.put(ApiMigration.Status_Error,TagColor.Warning);
            statusMap.put(ApiMigration.Status_Check,TagColor.Success);
            statusMap.put(ApiMigration.Status_Check_Done,TagColor.GeekBlue);
            statusMap.put(ApiMigration.Status_Migration,TagColor.Green);
            statusMap.put(ApiMigration.Status_Migration_Stop,TagColor.Red);
            statusMap.put(ApiMigration.Status_Done,TagColor.Purple);
        }
        return statusMap;
    }
    protected ListColumn getStatusColumn(String field){
        String dict="api.model.ApiMigration!status";
        return toElementColumn("状态", field, 100,
            ListElement.test("record.errorMessage",
                ListElement.tooltip("{{record.errorMessage}}",ListElement.dot(dict, getStatusColorMap()))
            ),
            ListElement.elseOther(ListElement.dot(dict, getStatusColorMap()))
        ).setAlign(Align.CENTER).setFilter(true).setDictType(dict);
    }
    /*
     * 数据迁移列表
     */
    public VueResult allList() throws Exception {
        VueListResult result=getVueListResult("数据迁移列表",ApiMigration.class,actionUrl("allList"));
        result.setSubTitle("相同应用之间的数据迁移");
        result.setFunction(true,false);
        result.setHeight(-1);
        result.addQueryFields("errorMessage");
        result.addCol(toIndexColumn());
        result.addCol(toLinkColumn("描述", "description", 150, true,
            new ListEvent(actionUrl("toView"),EventType.MODAL,1100)
                .addParam("model.oid","oid")
        ));
        result.addCol(toTextColumn("服务地址", "serverUrl", 100, true));
        result.addCol(toTextColumn("校验主键", "verifyOid", 100, true).setDictOption(ApiMigration.class,"verifyOid"));
        result.addCol(toTextColumn("迁移参数", "param", 100, true));
        result.addCol(toTextColumn("鉴权id", "authId", 100, true));
        result.addCol(toIntegerColumn("进程数量", "threadNum", 100, true));
        result.addCol(toIntegerColumn("记录数量", "recordNum", 100, true));
        result.addCol(toIntegerColumn("成功数量", "successNum", 100, true));
        result.addCol(toIntegerColumn("失败数量", "errorNum", 100, true));
        result.addCol(toNumberColumn("执行进度", "exeProgress", 100, true).setNumberFormat("0.00%").setCount(ListCount.NONE));
        result.addCol(getStatusColumn("status"));
        result.addCol(toSpaceColumn("操作", 130,
            ListElement.test("record.status=='"+ApiMigration.Status_Edit+"'||record.status=='"+ApiMigration.Status_Error+"'",
                ListButton.modal("修改", ButtonType.PRIMARY,actionUrl("toEdit"),800, SuccessMethod.REFRESH)
                    .addParam("model.oid","oid"),
                ListButton.ajax("删除", ButtonType.ERROR,actionUrl("doDelete"), SuccessMethod.REFRESH)
                    .addParam("model.oid","oid").setConfirm("确定要删除吗？")
            ),
            ListElement.elseTest("record.status=='"+ApiMigration.Status_Check_Done+"'",
                ListButton.modal("修改", ButtonType.PRIMARY,actionUrl("toEdit"),800, SuccessMethod.REFRESH)
                    .addParam("model.oid","oid"),
                ListButton.ajax("开始迁移", ButtonType.SUCCESS,actionUrl("doMigration"), SuccessMethod.REFRESH)
                    .addParam("model.oid","oid").setConfirm("确定要开始迁移数据吗？")
            ),
            ListElement.elseTest("record.status=='"+ApiMigration.Status_Migration_Stop+"'",
                ListButton.ajax("继续迁移", ButtonType.SUCCESS,actionUrl("doMigration"), SuccessMethod.REFRESH)
                    .addParam("model.oid","oid").setConfirm("确定要继续迁移数据吗？")
            ),
            ListElement.elseTest("record.status=='"+ApiMigration.Status_Migration+"'",
                ListButton.ajax("暂停迁移", ButtonType.WARN,actionUrl("stopMigration"), SuccessMethod.REFRESH)
                    .addParam("model.oid","oid").setConfirm("确定要开始迁移数据吗？")
            )
        ).setFixed(Align.RIGHT));
        result.addButton(
            ListButton.modal("新增", ButtonType.PRIMARY,actionUrl("toEdit"),800, SuccessMethod.REFRESH)
        );
        //排序 result.addOrder
        //查询条件 result.addCondition
        return result;
    }

    public ApiMigration getModel() {
        return model;
    }

    public void setModel(ApiMigration model) {
        this.model = model;
    }
}
